package com.zz.common.api

import cats.data.OptionT
import cats.effect.IO
import cats.implicits._
import com.zz.idl.{IdBundle, QueryZid, ZidWrapper}
import com.zz.common.service.IdService.Zidservice
import io.circe.generic.auto._
import io.circe.syntax._
import org.http4s._
import org.http4s.circe._
import org.http4s.dsl.io._

class TestEndpoint(zidService: Zidservice[IO]) {
  private implicit val idBundleEncoder: EntityDecoder[IO, IdBundle]        = jsonOf[IO, IdBundle]
  private implicit val idBundlesEncoder: EntityDecoder[IO, List[IdBundle]] = jsonOf[IO, List[IdBundle]]
  private implicit val queryZidEncoder: EntityDecoder[IO, QueryZid]        = jsonOf[IO, QueryZid]

  val endpoint: HttpRoutes[IO] = HttpRoutes.of[IO] {
    case req @ POST -> Root / "v0" / "add-id-bundle" =>
      (for {
        idBundle <- OptionT.liftF(req.as[IdBundle])
        zid      <- zidService.storeOrUpdate(idBundle)
        resp     <- OptionT.liftF(Ok(ZidWrapper(zid).asJson))
      } yield resp).getOrElseF(Ok(ZidWrapper("").asJson))
  } <+> HttpRoutes.of[IO] {
    case req @ POST -> Root / "v0" / "add-id-bundles" =>
      (for {
        idBundles <- OptionT.liftF(req.as[List[IdBundle]])
        zids      <- zidService.storeOrUpdateInBatch(idBundles)
        resp      <- OptionT.liftF(Ok(zids.map(ZidWrapper(_)).asJson))
      } yield resp).getOrElseF(Ok(Nil.asJson))
  } <+> HttpRoutes.of[IO] {
    case req @ GET -> Root / "v0" / "query-zid" =>
      (for {
        query  <- OptionT.liftF(req.as[QueryZid])
        id     = query.id
        idType = query.`type`
        zid    <- zidService.queryZid(id, idType)
        resp   <- OptionT.liftF(Ok(ZidWrapper(zid).asJson))
      } yield resp).getOrElseF(Ok(ZidWrapper("").asJson))
  }
}

object TestEndpoint {
  def apply(zidService: Zidservice[IO]): HttpRoutes[IO] = (new TestEndpoint(zidService)).endpoint
}
